#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <iomanip>

#include <cstring>
#define DEFAULT_INPUT		(3)

#if 0 == DEFAULT_INPUT
#define M1 6    //输入图像的行号
#define N1 6 //输入图像的列号 
#define M2 3    //卷积核的行号
#define N2 3 //卷积核的列号
#elif 1 == DEFAULT_INPUT
#define M1 3    //输入图像的行号
#define N1 3 //输入图像的列号 
#define M2 3    //卷积核的行号
#define N2 3 //卷积核的列号
int in1[M1][N1] = {
	1, 2, 3,
	4, 5, 6,
	7, 8, 9,
};
int mask[M2][N1] = {
	-1, -2, -1,
	0, 0, 0,
	1, 2, 1,
};
#elif 3 == DEFAULT_INPUT
#define M1 8    //输入图像的行号
#define N1 8 //输入图像的列号 
#define M2 3    //卷积核的行号
#define N2 3 //卷积核的列号
int in1[M1][N1] = {
	{3, 1, 1, 4, 8, 2, 1, 3},
	{4, 2, 1, 1, 2, 1, 2, 3},
	{4, 4, 4, 4, 3, 2, 2, 2},
	{9, 8, 3, 8, 9, 0, 0, 0},
	{9, 3, 3, 9, 0, 0, 0, 0},
	{0, 9, 0, 8, 0, 0, 0, 0},
	{3, 0, 8, 8, 9, 4, 4, 4},
	{5, 9, 8, 1, 8, 1, 1, 1},
};
int mask[M2][N2] = {
	{1, 1, 1},
	{1, 0, 1},
	{1, 1, 1},
};
#elif 2 == DEFAULT_INPUT
#define M1 5    //输入图像的行号
#define N1 5 //输入图像的列号 
#define M2 3    //卷积核的行号
#define N2 3 //卷积核的列号
int in1[M1][N1] = {
	1, 1, 1, 0, 0,
	0, 1, 1, 1, 0,
	0, 0, 1, 1, 1,
	0, 0, 1, 1, 0,
	0, 1, 1, 0, 0,
};
int mask[M2][N2] = {
	1, 0, 1,
	0, 1, 0,
	1, 0, 1,
};
#else
#define M1 4    //输入图像的行号
#define N1 3 //输入图像的列号 
#define M2 2    //卷积核的行号
#define N2 3 //卷积核的列号
int in1[M1][N1] = {
	1, 4, 5,
	2, 5, 6,
	3, 5, 6,
	7, 8, 9,
};
int mask[M2][N2] = {
	1, 2, 3,
	5, 6, 7,
};
#endif
void math_convolve(int input[M1][N1], const int input_w, const int input_h, int kern[N1][N2], const int kern_w, const int kern_h, int output[M1+M2-1][N1+N2-1], int output_w, int output_h)
{
	// 初始化为0



}

int cpu_twodimconvolution(void)
{
	int input_w = M1;
	int input_h = N1;
	int kern_w = M2;
	int kern_h = N2;
	int out_w = input_w + kern_w - 1;
	int out_h = input_h + kern_h - 1;
	int val = 0;
	int input[input_w][input_h];
	int kern[kern_w][kern_h];
	int rorate[kern_w][kern_h];
	int out[out_w][out_h];
    int i, j, m, n;
	int offset_w = 3;
	int offset_h = 3;
	offset_w = input_w;
	offset_h = input_h;
	std::cout << "line:" << __LINE__ << " input_w=" << input_w << "  input_h=" << input_h << std::endl;
	std::cout << "line:" << __LINE__ << " offset_w=" << offset_w << "  offset_h=" << offset_h << std::endl;
	std::cout << "line:" << __LINE__ << " kern_w=" << kern_w << "  kern_h=" << kern_h << std::endl;
	std::cout << "line:" << __LINE__ << " out_w=" << out_w << "  out_h=" << out_h << std::endl;
#if 0 == DEFAULT_INPUT
	std::cout << "line:" << __LINE__ << " if 0 == DEFAULT_INPUT" << std::endl;
	val = 1;
	for (int i = 0; i < input_w; i++)
	{
		for (int j = 0; j < input_h; j++)
		{
			input[i][j] = val++;
		}
	}
	val = 1;
	for (int i = 0; i < kern_w; i++)
	{
		for (int j = 0; j < kern_h; j++)
		{
			kern[i][j] = val++;
		}
	}

#elif 1 == DEFAULT_INPUT
	std::cout << "line:" << __LINE__ << " elif 1 == DEFAULT_INPUT" << std::endl;
	val = 1;
	for (int i = 0; i < input_w; i++)
	{
		for (int j = 0; j < input_h; j++)
		{
			input[i][j] = in1[i][j];
		}
	}
	val = 1;
	for (int i = 0; i < kern_w; i++)
	{
		for (int j = 0; j < kern_h; j++)
		{
			kern[i][j] = mask[i][j];
		}
	}
#elif 2 == DEFAULT_INPUT
	std::cout << "line:" << __LINE__ << " elif 2 == DEFAULT_INPUT" << std::endl;
	val = 1;
	for (int i = 0; i < input_w; i++)
	{
		for (int j = 0; j < input_h; j++)
		{
			input[i][j] = in1[i][j];
		}
	}
	val = 1;
	for (int i = 0; i < kern_w; i++)
	{
		for (int j = 0; j < kern_h; j++)
		{
			kern[i][j] = mask[i][j];
		}
	}
#elif 3 == DEFAULT_INPUT
	std::cout << "line:" << __LINE__ << " elif 3 == DEFAULT_INPUT" << std::endl;
	val = 0;
	for (int i = 0; i < input_w; i++)
	{
		for (int j = 0; j < input_h; j++)
		{
			input[i][j] = (input_w * input_h - val++);//in1[i][j];
		}
	}
	val = 1;
	for (int i = 0; i < kern_w; i++)
	{
		for (int j = 0; j < kern_h; j++)
		{
			kern[i][j] = 1;//mask[i][j];
		}
	}
#else
	std::cout << "line:" << __LINE__ << " else ? == DEFAULT_INPUT" << std::endl;
	val = 1;
	for (int i = 0; i < input_w; i++)
	{
		for (int j = 0; j < input_h; j++)
		{
			input[i][j] = val++;//in1[i][j];
		}
	}
	val = 1;
	for (int i = 0; i < kern_w; i++)
	{
		for (int j = 0; j < kern_h; j++)
		{
			kern[i][j] = val;//mask[i][j];
		}
	}
#endif
	val = 0;
	for (int i = 0; i < out_w; i++)
	{
		for (int j = 0; j < out_h; j++)
		{
			out[i][j] = val;
		}
	}
	std::cout << "line:" << __LINE__ << " input!" << std::endl;
	for (int i = 0; i < input_w; i++)
	{
		for (int j = 0; j < input_h; j++)
		{
			std::cout << " " << std::setw(4) << input[i][j];
		}
		std::cout << std::endl;
	}
	std::cout << std::endl;
	std::cout << "line:" << __LINE__ << " kern!" << std::endl;
	for (int i = 0; i < kern_w; i++)
	{
		for (int j = 0; j < kern_h; j++)
		{
			std::cout << " " << std::setw(4) << kern[i][j];
		}
		std::cout << std::endl;
	}
	std::cout << std::endl;
#if 1
	for (int i = 0; i < kern_w; i++)
	{
		for (int j = 0; j < kern_h; j++)
		{
			rorate[i][j] = kern[kern_w - 1 - i][kern_h - 1 - j];
		}
	}
	for (int i = 0; i < kern_w; i++)
	{
		for (int j = 0; j < kern_h; j++)
		{
			kern[i][j] = rorate[i][j];
		}
	}
	std::cout << "line:" << __LINE__ << " rorate then kern!" << std::endl;
	for (int i = 0; i < kern_w; i++)
	{
		for (int j = 0; j < kern_h; j++)
		{
			std::cout << " " << std::setw(4) << kern[i][j];
		}
		std::cout << std::endl;
	}
	std::cout << std::endl;
#endif

#if 0
	std::cout << "line:" << __LINE__ << "  math_convolve (full sample valid)" << std::endl;
    for (i = 0; i < out_w; i++)
    {
        for (j = 0; j < out_h; j++)
        {
            int temp = 0;
            for (m = 0; m < input_w; m++)
            {
                for (n = 0; n < input_h; n++)
                    if ((i - m) >= 0 && (i - m)<kern_w && (j - n) >= 0 && (j - n)<kern_h)
                        temp += input[m][n] * kern[kern_w - 1 - (i - m)][kern_h - 1 - (j - n)];
                out[i][j] = temp;
            }
        }
    }
#else
	std::cout << "line:" << __LINE__ << " math_update_convolve (full sample valid)" << std::endl;
	for (i = 0; i < kern_w; i++)
    {
        for (j = 0; j < kern_h; j++)
        {
			for (m = 0; m < input_w; m++)
			{
				for (n = 0; n < input_h; n++)
				{
					out[i + m ][j + n] += kern[i][j] * input[m][n];
				}
			}
        }
    }

#endif
	//math_convolve(input, input_len, kern, kern_len, out, out_len);
	out_w = input_w + kern_w - 1;
	out_h = input_h + kern_h - 1;
	std::cout << "line:" << __LINE__ << " out_w=" << out_w << "  out_h=" << out_h << std::endl;
	if ((out_w == (input_w + kern_w - 1)) && (out_h == (input_h + kern_h - 1)))
	{
		offset_w = 0;
		offset_h = 0;
		std::cout << "line:" << __LINE__ << " full mode!" << std::endl;

		for (int i = 0; i < out_w; i++)
		{
			for (int j = 0; j < out_h; j++)
			{
				std::cout << " " << std::setw(4) << out[i + offset_w][j + offset_h];
			}
			std::cout << std::endl;
		}
		std::cout << std::endl;
	}
#if 1
	out_w = input_w;
	out_h = input_h;
	std::cout << "line:" << __LINE__ << " out_w=" << out_w << "  out_h=" << out_h << std::endl;
	if ((out_w == input_w) && (out_h == input_h))
	{
		offset_w = int((kern_w - 1) / 2);
		offset_h = int((kern_h - 1) / 2);
	    std::cout << "line:" << __LINE__ << " same mode!" << std::endl;

		for (int i = 0; i < out_w; i++)
		{
			for (int j = 0; j < out_h; j++)
			{
				std::cout << " " << std::setw(4) << out[i + offset_w][j + offset_h];
			}
			std::cout << std::endl;
		}
		std::cout << std::endl;
	}

	out_w = input_w - kern_w + 1;
	out_h = input_h - kern_h + 1;
	std::cout << "line:" << __LINE__ << " out_w=" << out_w << "  out_h=" << out_h << std::endl;
	if ((out_w == (input_w - kern_w + 1)) && (out_h == (input_h - kern_h + 1)))
	{
		std::cout << "line:" << __LINE__ << " offset_w=" << offset_w << "  offset_h=" << offset_h << std::endl;
	    std::cout << "line:" << __LINE__ << " valid mode!" << std::endl;
		offset_w = int((kern_w - 1) / 1);
		offset_h = int((kern_h - 1) / 1);

		for (int i = 0; i < out_w; i++)
		{
			for (int j = 0; j < out_h; j++)
			{
				std::cout << " " << std::setw(4) << out[i + offset_w][j + offset_h];
			}
			std::cout << std::endl;
		}
		std::cout << std::endl;
	}
#endif
	std::cout << "  Two Dim convolve sucessfully!" << std::endl;
	
    return 0;
}
